Artículo RBM

Abstract

El presente artículo tiene como finalidad entender con mayor profundidad la dinámica de transporte en la Zona Metropolitana del Valle de México (ZMVM), en donde existe una marcada desigualdad en el acceso a medios de transporte. Esto se realiza a través del desarrollo de redes bayesianas multinomiales, las cuales captan las dependencias entre las diferentes variables en las que la investigación se enfoca, como el sexo, el estrato sociodemográfico, el uso de transporte público o privado, el horario en el que se viaja, entre otras. Se utilizaron datos del Instituto Nacional de Estadística y Geografía (INEGI) en la Encuesta Origen-Destino en Hogares de la ZMVM del 2017, con lo que se propusieron los grafos acíclicos dirigidos que sirven como la estructura de la red bayesiana. Estos grafos fueron comparados entre sí y se optimizó la estructura con el algoritmo de hill climbing, con lo cual se respondieron las consultas con respecto a la dinámica de transporte en la ZMVM. Uno de los resultados más relevantes fue que las mujeres son menos probables a utilizar transporte público a comparación de los hombres, lo cual podría deberse a causas de género, como el acoso. Además, se encontró que el uso del transporte público es menos probable cuando se realiza un viaje en hora pico a comparación de cuando se viaja en una hora no pico. El artículo se encuentra limitado respecto a la definición de algunas de las variables de interés, como el viajar en horario pico, lo cual afecta al resultado de algunas consultas.

Palabras clave: Transporte, Zona Metropolitana del Valle de México, estrato sociodemográfico, análisis, redes bayesianas multinomiales, grafo acíclico dirigido, probabilidad.

Introducción

La movilidad urbana constituye un componente esencial en la calidad de vida de los habitantes de las grandes ciudades, al incidir directamente en el acceso a oportunidades educativas, laborales y recreativas. En particular, la Zona Metropolitana del Valle de México (ZMVM) enfrenta desde hace décadas retos asociados con la saturación vial, la desigualdad en el acceso a medios de transporte, y la alta dependencia del automóvil privado. (Alfonso, Alberto, and Alfonso 2020)

“En una región caracterizada por la desigualdad, las deficiencias de los sistemas de transporte público impactan de forma desproporcionada a los más vulnerables. Solamente el 43% de la población de América Latina y el Caribe tiene acceso conveniente al transporte público, y sus usuarios gastan 70% más tiempo en el desplazamiento al trabajo comparados a quienes utilizan vehículos privados”. (Plataforma Urbana y de Ciudades 2023)

En 2017, el Instituto Nacional de Estadística y Geografía (INEGI), en colaboración con el Instituto de Ingeniería de la UNAM y la Secretaría de Movilidad de la Ciudad de México, llevó a cabo la “Encuesta Origen-Destino en Hogares de la ZMVM”. (INEGI 2017) Este levantamiento tuvo como propósito caracterizar los desplazamientos diarios de los habitantes de la metrópoli, registrando variables como motivo del viaje, duración, medio de transporte, horarios de salida y llegada, así como información sociodemográfica de los hogares y personas encuestadas.

El presente artículo se centra en responder cuatro consultas específicas de esta base de datos generada por el INEGI:

  1. ¿Cuál es la probabilidad de que una mujer utilice el transporte público en comparación con un hombre?

  2. ¿Qué tan probable es que una persona tenga más de un automóvil o utilice transporte privado, dado que se trata de un hombre entre 20 y 45 años con estrato sociodemográfico bajo?

  3. ¿Las personas con un estrato sociodemográfico bajo realizan más viajes en días hábiles que en días inhábiles?

  4. ¿Cuál es la probabilidad de que una persona utilice transporte público durante las horas pico en comparación con las horas de menor tráfico?

Dado que la movilidad está influenciada por diversos factores interrelacionados resulta difícil explicar estas relaciones con un enfoque únicamente determinista. El uso de modelos probabilísticos ofrece una manera más robusta de capturar estas interacciones y de responder a las preguntas planteadas.

La idea central de este razonamiento probabilístico se basa en el teorema de Bayes y en las probabilidades condicionales para modelar las relaciones entre distintos eventos. En lugar de afirmar con certeza que “mañana lloverá”, este enfoque permite expresar escenarios más realistas, como decir que “existe un 70% de probabilidad de que mañana llueva”. (Bhattarai 2025)

El Teorema de Bayes, permite actualizar la probabilidad de una hipótesis H al observar nueva evidencia E:

\begin{equation} P(H | E) = \frac{P(E | H)P(H)}{P(E)} \end{equation}

Donde P(H) es la probabilidad previa de la hipótesis, P(E|H) es la probabilidad de observar la evidencia dado que H es cierta, y P(H|E) es la probabilidad posterior, actualizada después de incorporar la evidencia.

Una red bayesiana es un modelo gráfico probabilístico que utiliza un grafo acíclico dirigido (DAG, por sus siglas en inglés, Directed Acyclic Graph) para describir un conjunto de variables y sus relaciones condicionales . Las redes bayesianas funcionan para pronosticar un evento que ya ha ocurrido y predecir la probabilidad de que el factor contribuyente esté entre varias causas conocidas.

Metodología

Formalmente, una red bayesiana se define como el par (G,P), donde G=(V,E) es un DAG cuyos nodos V=\{X_1,X_2,…,X_n\}, corresponden a las variables de interés y los arcos E representan dependencias directas, mientras que P es el conjunto de distribuciones de probabilidad condicional asociadas a cada nodo. La probabilidad conjunta de todas las variables se factoriza como:

\begin{equation} P(X_1, X_2, \dots, X_n) = \prod_{i=1}^{n} P(X_i | \text{Parents}(X_i)) \end{equation}

Esta estructura permite analizar relaciones de dependencia complejas, realizar inferencias sobre escenarios hipotéticos y evaluar cómo distintos factores individuales y contextuales influyen en los patrones de transporte en la ZMVM.

Las redes bayesianas multinomiales ofrecen una herramienta poderosa para modelar interacciones probabilísticas entre variables, permitiendo no sólo estimar la probabilidad de determinados comportamientos de viaje, sino también evaluar cómo cambian dichas probabilidades bajo distintos escenarios.

Para dar respuesta a las preguntas, se trabajará con información proveniente de distintos módulos de la encuesta, de los cuales se extraerán variables clave, estas son: sexo, edad, estrato sociodemográfico, número de automóviles disponibles, clasificación del día y hora del viaje, así como el medio de transporte empleado. El análisis busca identificar dependencias significativas entre estas variables y aportar evidencia sobre cómo factores individuales y contextuales inciden en la movilidad dentro de la ZMVM.

Para crear los modelos que se presentarán posteriormente, se identificaron las siguientes variables de interés a partir de las preguntas dadas.

  • sexo: Mujer, Hombre
  • tipoTransporte: Ninguno, Publico, Privado, Publico y privado
  • masDeUnCarro: No, Si
  • edad: Joven, Adulto joven, Adulto, Adulto mayor
  • estrato: Bajo, Medio bajo, Medio alto, Alto
  • diaViaje: Entre semana, Sabado
  • horaPico: No, Si

Es de notar, que las primeras dos preguntas tratan sobre las personas que realizaron los viajes, mientras que las últimas dos hablan sobre los viajes como tal, y dado que una persona puede tener varios viajes registrados, se crearán dos bases de datos desde la base original. En la primera, cada registro corresponde a una persona, mientras que en la segunda, cada registro corresponde a un viaje.

Lo anterior implica que las variables dentro de cada base de datos pueden diferir, pues por ejemplo, si un viaje se realizó en hora pico solamente tiene sentido en una base de datos sobre viajes, no sobre personas (como se mencionó, una persona puede tener varios viajes, con solamente algunos realizados durante hora pico). Las variables que se utilizarán para las primeras dos preguntas son: sexo, edad, estrato, tipoTransporte y masDeUnCarro; el proceso para obtenerlas se puede consultar en el Apéndice A. Por otro lado, las variables para responder las últimas dos preguntas son: tipoTransporte, estrato, diaViaje y horasPico, el proceso de su obtención se encuentra en el Apéndice B.

Habiendo identificado las variables de interés y procesado de datos, se realizarán dos propuestas de DAGs para cada base de datos, con sus respectivas variables. Estos grafos representan las relaciones de dependencia que se considera intuitivamente podrían existir entre las variables.

Con cada una de las DAGs propuestas, se generará una red bayesiana, con la cual se realizarán pruebas de independencia condicional para cada arco. Esto permitirá determinar la significancia de las relaciones propuestas entre las variables, así como ver cuál de las redes representa un mejor ajuste para los datos.

La prueba de independencia condicional que se utilizará para probar la significancia de un arco entre dos variables de los grafos estará basada en el criterio de información mutua, la cual mide qué tanta información es compartida entre dos nodos, de la librería de bnlearn de R. (Kratzer et al. 2023)

Posteriormente, se generará una DAG óptima para cada base de datos con el algoritmo de hill climbing. Este algoritmo busca optimizar un criterio dado, mientras elimina y agrega un arco a la vez, escogiendo el movimiento que represente la mayor mejora del criterio. El criterio a maximizar será el de información bayesiano (BIC), al ser este un criterio empleado para la selección del mejor modelo entre una cantidad finita de modelos, considerando la verosimilitud y la complejidad de los modelos. (Scutari and Denis 2021)

A pesar de que el algoritmo de hill climbing genera un DAG óptimo respecto a la métrica del BIC, es necesario considerar la pertinencia de las relaciones que genera, ya que este no conoce el contexto de las variables o lo que representan y podría poner una relación que no tiene sentido.

Una vez habiendo seleccionado los DAGs óptimos para cada conjunto de datos, se responderán las preguntas primero estableciendo las probabilidades esperadas, con las cuales se realizará inferencia exacta o aproximada, dependiendo del caso. Si se puede obtener una probabilidad directamente de la red bayesiana generada, se realizará esto. En caso contrario, se estimará la probabilidad utilizando el método de Monte Carlo, realizando múltiples simulaciones del modelo que se resumirán en el estimador de interés. Para ello, se utilizará el algoritmo logic sampling, el cual simula observaciones de la red bayesiana que son independientes entre sí, y estima la probabilidad con la cantidad de observaciones que cumplen el evento sobre la cantidad de observaciones que cumplen con la evidencia. (Scutari and Denis 2021)

Aplicación

Preprocesamiento de los datos

Previo a implementar las propuestas de los DAGs y determinar el mejor modelo para responder a las preguntas, se realizó primeramente la limpieza de los datos de la encuesta del INEGI. Para ello, se generó primero un archivo en donde se encuentran las variables de interés de las primeras dos preguntas, las cuales son:

  • sexo: El sexo de la persona encuestada.
  • edad: El rango de edad de la persona encuestada.
  • tipoTransporte: Indica si la persona utilizó transporte público, privado, ambos o ninguno para viajar.
  • masDeUnCarro: Indica si la persona cuenta con más de un carro o no.
  • estrato: Indica el estrato sociodemográfico de la persona encuestada.

El desarrollo de este conjunto de datos es descrito en el Apéndice A. El código para dicho procedimiento es el siguiente:

## Importar librerias y leer datos
library(tidyverse)
library(dplyr)

vivienda = read.csv("eod_2017_csv/tvivienda_eod2017/conjunto_de_datos/tvivienda.csv")
viaje = read.csv("eod_2017_csv/tviaje_eod2017/conjunto_de_datos/tviaje.csv")
transporte = read.csv("eod_2017_csv/ttransporte_eod2017/conjunto_de_datos/ttransporte.csv")
sociodem = read.csv("eod_2017_csv/tsdem_eod2017/conjunto_de_datos/tsdem.csv")
hogar = read.csv("eod_2017_csv/thogar_eod2017/conjunto_de_datos/thogar.csv")

## Data frame queries 1 y 2
df = unique(viaje[c("id_soc", "sexo", "edad")])

# Renombrar sexo a partir del catalogo
sexos = read.csv("eod_2017_csv/tviaje_eod2017/catalogos/sexo.csv")
df$sexo = factor(df$sexo, labels=sexos$descrip)

# Agrupar edades
df$edad[which(df$edad < 20)] = 0
df$edad[which((df$edad >= 20) & (df$edad < 46))] = 1
df$edad[which((df$edad >= 46) & (df$edad < 65))] = 2
df$edad[which(df$edad >= 65)] = 3
df$edad = factor(df$edad, labels=c("Joven", "Adulto joven", "Adulto", "Adulto mayor"))

# unión de viaje con transporte en dataframe temporal
df_temp = right_join(viaje[c("id_via", "id_soc")], transporte[c("id_via", "p5_14")], "id_via")
df_temp = right_join(df, df_temp, "id_soc")
df_temp$transporte_pub = df_temp$p5_14 %in% c(2, 5, 6, 8, 10, 11, 12, 13, 15)
df_temp$transporte_priv = df_temp$p5_14 %in% c(1, 3, 4, 7, 9, 14, 16, 17, 18, 19)

# Tipo de transporte
df$transporte_pub = right_join(df, aggregate(df_temp$transporte_pub, by = list(id_soc = df_temp$id_soc), FUN=sum), "id_soc")$x
df$transporte_pub[which(df$transporte_pub > 0)] = 1
df$transporte_priv = right_join(df, aggregate(df_temp$transporte_priv, by = list(id_soc = df_temp$id_soc), FUN=sum), "id_soc")$x
df$transporte_priv[which(df$transporte_priv > 0)] = 2
df$tipoTransporte = df$transporte_priv + df$transporte_pub
df$tipoTransporte = factor(df$tipoTransporte, labels=c("Ninguno", "Publico", "Privado", "Publico y privado"))

# Cantidad de carros y estrato sociodemográfico
hogar_sociodem <- right_join(hogar[c("id_hog", "p2_1_1", "estrato")], sociodem[c("id_soc", "id_hog")], "id_hog")
df_temp <- right_join(hogar_sociodem[c("id_soc", "p2_1_1", "estrato")], viaje["id_soc"], "id_soc")
df <- left_join(df, unique(df_temp[c("id_soc", "p2_1_1", "estrato")]), "id_soc")
colnames(df)[which(names(df) == "p2_1_1")] <- "masDeUnCarro"
df$masDeUnCarro[which(df$masDeUnCarro > 1)] = 2
df$masDeUnCarro[which(df$masDeUnCarro == 1)] = 0
df$masDeUnCarro = factor(df$masDeUnCarro, labels=c("No", "Si"))

# Renombrar estratos sociodemográficos a partir del catalogo
estratos = read.csv("eod_2017_csv/thogar_eod2017/catalogos/estrato.csv")
df$estrato = factor(df$estrato, labels=estratos$descrip)

# Eliminar columnas innecesarias
df = df[, !names(df) %in% c("id_soc", "transporte_pub", "transporte_priv")]

# Guardar datos en csv
write.csv(df, file="q12.csv", row.names=F)

Análogamente, se creó el conjunto de datos para las preguntas 3 y 4, cuyas variables de interés son:

  • diaViaje: Indica si el viaje se llevó a cabo entre semana o en sábado.
  • estrato: Indica el estrato sociodemográfico de la persona que realiza el viaje.
  • tipoTransporte: Indica si durante el viaje se utilizó transporte público, privado, ambos o ninguno.
  • horaPico: Indica si más de la mitad del viaje se realizó en hora pico.

El desarrollo de este conjunto de datos es descrito en el Apéndice B. El código para dicho procedimiento es el siguiente:

## Data frame queries 3 y 4
df = viaje[c("id_via", "p5_3", "p5_9_1", "p5_9_2", "p5_10_1", "p5_10_2", "estrato")]

# Día en el que se realiza el viaje
df$diaViaje = factor(df$p5_3, labels=c("Entre semana", "Sabado"))

# Renombrar estratos sociodemográficos a partir del catalogo
df$estrato = factor(df$estrato, labels=estratos$descrip)

# Usar transporte público en cierto viaje
df_temp = right_join(transporte[c("id_via", "p5_14")], viaje[c("id_via")], "id_via") # Medio de transportes por viaje
df_temp$transporte_pub = df_temp$p5_14 %in% c(2, 5, 6, 8, 10, 11, 12, 13, 15)
df_temp$transporte_priv = df_temp$p5_14 %in% c(1, 3, 4, 7, 9, 14, 16, 17, 18, 19)
df$transporte_pub = right_join(df, aggregate(df_temp$transporte_pub, by=list(id_via=df_temp$id_via), FUN=sum), "id_via")$x
df$transporte_pub[which(df$transporte_pub > 0)] = 1
df$transporte_priv = right_join(df, aggregate(df_temp$transporte_priv, by=list(id_via=df_temp$id_via), FUN=sum), "id_via")$x
df$transporte_priv[which(df$transporte_priv > 0)] = 2
df$tipoTransporte = df$transporte_priv + df$transporte_pub
df$tipoTransporte = factor(df$tipoTransporte, labels=c("Ninguno", "Publico", "Privado", "Publico y privado"))

# Determinar si el viaje se realizo en hora pico o no
# Convertimos todo a minutos para hacer mas facil la chamba
df$start <- df$p5_9_1*60 + df$p5_9_2
df$end <- df$p5_10_1*60 + df$p5_10_2

# Ajustamos viajes que cruzan medianoche
df$end[df$start > df$end] <- df$end[df$start > df$end] + 24*60

# Calculo de la duracion del viaje
df$duracion <- df$end-df$start+1

# Calculo de minutos en hora pico
# Primer intervalo de hora pico: 7:30-9:30 (en minutos [450, 570])
# Segundo intervalo de hora pico: 17:30-20:00 (en minutos [1050, 1200])
df$minutos_pico <- pmax(0, pmin(df$end, 570) - pmax(df$start, 450)) + # traslape primera hora pico
                    pmax(0, pmin(df$end, 1050) - pmax(df$start, 1200)) + # traslape segunda hora pico
                    pmax(0, pmin(df$end, 24*60+1050) - pmax(df$start, 24*60+1200)) + # traslape primera hora pico dia siguiente
                    pmax(0, pmin(df$end, 24*60+1050) - pmax(df$start, 24*60+1200)) # traslape segunda hora pico dia siguiente


# Porcentaje de duración en hora pico
df$porcentaje_pico <- df$minutos_pico / df$duracion

# Hora pico sí/no
df$horaPico <- factor(ifelse(df$porcentaje_pico > 0.5, "Si", "No"))

# Seleccionar columnas con variables de interes
df = df[, c("estrato", "diaViaje", "tipoTransporte", "horaPico")]
  
# Guardar datos en csv
write.csv(df, file="q34.csv", row.names=F)

Propuestas de DAGs

Primeramente, se presentarán dos propuestas para las dependencias entre variables para las primeras dos preguntas (lo que llevará a una primera propuesta de grafo dirigido):

En esta primera red, se establecen sexo y edad como variables independientes, pues estas dependen totalmente de la persona y no son influenciadas por factores externos. Así mismo, se asumirá que la edad tiene una influencia directa con el estrato socioeconómico pues consideramos que a mayor edad más probable era que exista un patrimonio establecido y con ello un estrato más alto, mientras que el sexo puede tener una influencia debido a las brechas salariales y factores de género. De igual manera, se considerará que el estrato tiene una influencia en si la persona tiene más de un carro, pues con un mejor nivel económico también crece la posibilidad de adquisición de este tipo de bienes. Finalmente, establecimos que tanto el estrato socioeconómico como si la persona tiene más de un carro influyen en el tipo de transporte que se utilizará, pues si se cuenta con la posibilidad económica, es probable que se elija utilizar medios de transporte particulares.

Las relaciones anteriores llevan al siguiente grafo dirigido que será utilizado para la primera red bayesiana:

flowchart TD
    s(sexo) --> e(estrato)
    ed(edad) --> e
    e --> mc(masDeUnCarro)
    e --> tt(tipoTransporte)
    mc --> tt

Utilizando esta DAG, podemos factorizar la distribución de probabilidad global de este conjunto de variables de la siguiente manera: \mathbb{P}(sexo,edad,estrato,masDeunCarro,tipoTransporte)=\mathbb{P}(sexo) \,\mathbb{P}(edad)\, \mathbb{P}(estrato|edad,sexo) \\ \mathbb{P}(masDeUnCarro|estrato) \,\mathbb{P}(tipoTransporte|masDeUnCarro,estrato)

La segunda propuesta sigue un formato similar pero con relaciones distintas a lo previamente realizado. Nuevamente, tanto el sexo como la edad fueron consideradas variables independientes pues dependen únicamente de la persona. Además, se consideró que el sexo tiene influencia en el estrato por las razones ya mencionadas. Por otro lado, decidimos asumir que además del estrato como factor para tener más de un carro, la edad también es un factor influyente. Finalmente, decidimos que el tipo de transporte utilizado depende únicamente de si la persona tiene más de un carro, pues con la adquisición de uno es más probable que se elija la opción de utilizar un transporte privado.

Las relaciones anteriores pueden ser representadas con la siguiente DAG:

flowchart TD
    s(sexo) --> e(estrato)
    e --> mc(masDeUnCarro)
    ed(edad) --> mc
    mc --> tt(tipoTransporte)

Con las relaciones propuestas anteriormente la factorización de la distribución global queda de la siguiente manera: \,\mathbb{P}(sexo,edad,estrato,masDeunCarro,tipoTransporte)=\mathbb{P}(sexo) \,\mathbb{P}(edad) \,\mathbb{P}(estrato|sexo) \\ \,\mathbb{P}(masDeUnCarro|estrato,edad) \,\mathbb{P}(tipoTransporte|masDeUnCarro)

Para evaluar la eficacia de ambos modelos, es necesario llevar a cabo distintas pruebas. Por ejemplo, para comprobar la significancia de las relaciones entre variables se realizarán pruebas de información mutua mencionada anteriormente. A continuación se presenta el proceso para llevar a cabo las pruebas para evaluar las relaciones propuestas en la primera DAG:

## Importar libreria y cargar datos
library(bnlearn)
#Para la primera query
data12 = read.csv("q12.csv", stringsAsFactors = TRUE)
#Segunda query
data34 = read.csv("q34.csv", stringsAsFactors = TRUE)

## Primera DAG propuesta
dag1 = empty.graph(nodes = c("sexo", "edad", "tipoTransporte", "masDeUnCarro", "estrato"))


arc_set = matrix(c("sexo", "estrato",
                   "edad", "estrato",
                   "estrato", "masDeUnCarro",
                   "estrato", "tipoTransporte",
                   "masDeUnCarro", "tipoTransporte"),
                 byrow = TRUE, ncol = 2,
                 dimnames = list(NULL, c("from", "to")))

arcs(dag1) = arc_set

## Evaluacion de arcos primera DAG
arc.strength(dag1, data = data12, criterion = "mi")
from to strength
sexo estrato 0.0052231
edad estrato 0.0000000
estrato masDeUnCarro 0.0000000
estrato tipoTransporte 0.0000000
masDeUnCarro tipoTransporte 0.0000000

Como podemos observar, ya que el p-value de todas las pruebas es menor a nuestro nivel de significancia de 0.05, podemos afirmar que en general las relaciones que habíamos propuesto entre variables están bien planteadas. Por otro lado, a continuación se presentan los resultados de la misma prueba llevada a cabo en la segunda DAG propuesta:

## Segunda DAG propuesta

dag2 = empty.graph(nodes = c("sexo", "edad", "tipoTransporte", "masDeUnCarro", "estrato"))

arc_set2 = matrix(c("sexo", "estrato",
                   "estrato", "masDeUnCarro",
                   "edad", "masDeUnCarro",
                   "masDeUnCarro", "tipoTransporte"),
                 byrow = TRUE, ncol = 2,
                 dimnames = list(NULL, c("from", "to")))
arcs(dag2) = arc_set2

## Evaluacion de arcos segunda DAG
arc.strength(dag2, data = data12, criterion = "mi")
from to strength
sexo estrato 0.1792488
estrato masDeUnCarro 0.0000000
edad masDeUnCarro 0.0000000
masDeUnCarro tipoTransporte 0.0000000

Nuevamente, todas las relaciones entre variables que propusimos en un inicio tienen un p-value menor a 0.05, por lo que también podemos afimar que fueron buenas propuestas. Es por esto, que también es necesario llevar a cabo otro tipo de pruebas, como el criterio de información bayesiano (BIC) mencionado con anterioridad. Esta prueba se lleva a cabo de la siguiente manera:

# Primera DAG
score(dag1, data = data12, type = "bic")
[1] -653115.9
# Segunda DAG
score(dag2, data = data12, type = "bic")
[1] -654467.1

Ya que el objetivo del BIC es su maximización, podemos darnos cuenta que el primer modelo propuesto presenta mejor adaptación a los datos presentados al tener un score más alto, por lo que puede ser mejor para su utilización en un cálculo de probabilidades.

Por otro lado, a continuación se presentan las dos propuestas de relaciones entre variables para las últimas dos preguntas, que nos permitirán hacer otros dos grafos dirigidos:

Para la primera propuesta, se considera el estrato como una variable independiente, pues como las preguntas que se intentan responder hablan sobre los viajes y no sobre las personas, el estrato del viajante no depende de algún factor externo. Así mismo, se asume que el estrato tiene una influencia directa sobre el tipo de transporte que se utiliza, pues el equipo consideró que a mayor estrato sociodemográfico la probabilidad de continuar utilizando transporte público tiende a disminuir, así mismo, para esta propuesta se asumirá que el mismo estrato tiene una influencia sobre el día de viaje en el que se realizó el viaje, pues con un mayor estrato existe una mayor posibilidad de salir los fines de semana. Finalmente, la última relación que se decidió incluir es la influencia del día del viaje sobre si se realizó en hora pico, debido a los cambios que pueden realizarse en los horarios de la persona durante los días de fin de semana.

Las anteriores relaciones de variables llevan al siguiente diagrama de grafo dirigido:

flowchart TD
    e(estrato) --> d(diaViaje)
    d --> h(horaPico)
    e --> t(tipoTransporte)

Con lo anterior previamente definido la factorización de la distribución global queda de la siguiente manera: \mathbb{P}(estrato,diaViaje,tipoTransporte,horaPico)=\mathbb{P}(estrato) \,\mathbb{P}(tipoTransporte|estrato) \\ \,\mathbb{P}(diaViaje|estrato) \,\mathbb{P}(horaPico|diaViaje)

Así mismo, se realizó otra propuesta de relaciones entre las variables que se presenta a continuación:

Nuevamente, se consideró al estrato como una variable independiente, así como que el día de viaje influye en si se realizó en hora pico, por otro lado, en esta ocasión también se decidió probar el día de viaje como una variable independiente. Finalmente, se consideró que el tipo de transporte depende tanto del estrato, por las mismas razones que en el grafo anterior; como del día, pues por ejemplo puede ser influenciado por factores como el hoy no circula; y si fue realizado en hora pico, ya que decidir no viajar en hora pico puede cambiar la decisión del tipo de transporte a utilizar; por lo que esta variable es dependiente de todas las demás.

Con todas estas relaciones entre variables establecidas llegamos al siguiente grafo dirigido:

flowchart TD
    a(estrato) --> b(tipoTransporte)
    c(diaViaje) --> d(horaPico)
    c --> b
    d --> b

El grafo anterior nos permite factorizar la distribución global como: \mathbb{P}(estrato,diaViaje,tipoTransporte,horaPico)=\mathbb{P}(estrato) \,\mathbb{P}(diaViaje) \,\mathbb{P}(horaPico|diaViaje) \\ \,\mathbb{P}(tipoTransporte|estrato,diaViaje,horaPico) Para la DAG #3

dag3 = empty.graph(nodes = c("estrato", "diaViaje", "tipoTransporte", "horaPico"))

arc_set3 = matrix(c("estrato", "diaViaje",
                      "diaViaje", "horaPico",
                      "estrato", "tipoTransporte"),
                    byrow = TRUE, ncol = 2,
                    dimnames = list(NULL, c("from", "to")))
arcs(dag3) = arc_set3

DAG #4

dag4 = empty.graph(nodes = c("estrato", "tipoTransporte", "diaViaje", "horaPico"))

arc_set4 = matrix(c("estrato", "tipoTransporte",
                    "diaViaje", "horaPico",
                    "diaViaje", "tipoTransporte",
                    "horaPico", "tipoTransporte"),
                  byrow = TRUE, ncol = 2,
                  dimnames = list(NULL, c("from", "to")))
arcs(dag4) = arc_set4

Volvemos a verificar la validez de las relaciones planteadas entre variables. Para ello se aplican nuevamente las pruebas basadas en información mutua, lo que permite determinar si los arcos definidos en la DAG están presentes en los datos.

arc.strength(dag3, data = data34, criterion = "mi")
from to strength
estrato diaViaje 0
diaViaje horaPico 0
estrato tipoTransporte 0
arc.strength(dag4, data = data34, criterion = "mi")
from to strength
estrato tipoTransporte 0
diaViaje horaPico 0
diaViaje tipoTransporte 0
horaPico tipoTransporte 0

Podemos observar que para ambas DAG, el p_value es menor al nivel de significancia de 0.05, por lo que podemos afirmar que las relaciones propuestas son relevantes.

De igual manera se calcula el puntaje BIC correspondiente a cada modelo, con el fin de comparar su ajuste.

score(dag3, data = data34, type = "bic")
[1] -1589939
score(dag4, data = data34, type = "bic")
[1] -1588677

Recordemos que una DAG con scores más altos ajusta mejor a los datos, por lo que concluimos que la mejor DAG para las queries 3 y 4 es la DAG #4

Finalmente empleamos el algoritmo de Hill Climbing para obtener el DAG con el puntaje óptimo en cada caso, y contrastarlo con las propuestas iniciales calculando también el puntaje BIC.

best_dag_q12 = hc(data12)
modelstring(best_dag_q12)
[1] "[sexo][edad|sexo][tipoTransporte|sexo:edad][masDeUnCarro|edad:tipoTransporte][estrato|edad:tipoTransporte:masDeUnCarro]"

flowchart TD
    s(sexo) --> ed(edad)
    s --> tt(tipoTransporte)
    ed --> tt
    ed --> mc(masDeUnCarro)
    tt --> mc
    ed --> e(estrato)
    tt --> e
    mc --> e

best_dag_q34 = hc(data34)
modelstring(best_dag_q34)
[1] "[estrato][diaViaje|estrato][tipoTransporte|estrato:diaViaje][horaPico|estrato:diaViaje:tipoTransporte]"

flowchart TD
    e(estrato) --> d(diaViaje)
    e --> tt(tipoTransporte)
    d --> tt
    e --> h(horaPico)
    d --> h
    tt --> h

score(best_dag_q12, data = data12, type = "bic")
[1] -650941
score(best_dag_q34, data = data34, type = "bic")
[1] -1588559

Observamos que las estructuras del algoritmo presentan un mejor puntaje BIC, indicando un ajuste superior a los datos. Por lo tanto, los modelos obtenidos con Hill-Climbing constituyen la mejor opción para el análisis probabilístico en estas consultas.

Pese a que el algoritmo generó el DAG que mejor se ajusta a los datos, es importante revisar la coherencia de las relaciones planteadas. En este caso, aparece una conexión entre sexo y edad, la cual no necesariamente tiene sentido.Por otro lado, podemos encontrar la relación de edad y más de un carro que incluimos en una de nuestras propuestas, reafirmando la decisión.

En este caso, el algoritmo generó un DAG en el que estrato influye en día de viaje y hora pico, y estas a su vez se relacionan con el tipo de transporte. A diferencia del ejemplo anterior, no encontramos inconsistencias lógicas en las conexiones, ya que las relaciones pueden explicarse desde el contexto de la movilidad. Podemos observar que esta DAG es muy parecida a la propuesta, tenemos las mismas relaciones pero el algoritmo encontró una más entre el estrato y la variable de horaPico.

Finalmente, con estos modelo, se pueden responder las preguntas planteadas en un inicio:

# Ajustamos las redes a los datos
fitted_q12 <- bn.fit(best_dag_q12, data = data12)
fitted_q34 <- bn.fit(best_dag_q34, data = data34)

# Query 1
prob_mujer <- cpquery(fitted_q12,
                      event = ((tipoTransporte == "Publico") | (tipoTransporte == "Publico y privado")),
                      evidence = (sexo == "Mujer"), n = 10^6)

prob_hombre <- cpquery(fitted_q12,
                       event = ((tipoTransporte == "Publico") | (tipoTransporte == "Publico y privado")),
                       evidence = (sexo == "Hombre"), n = 10^6)

prob_mujer
[1] 0.4914904
prob_hombre
[1] 0.5199084

Puede verse que la probabilidad de que una mujer utilice transporte público es menor respecto a la de un hombre con un 0.49 y 0.52 respectivamente. Esto podría indicar que las mujeres pueden tener una mayor tendencia a buscar alternativas al transporte público, que podrían ser debido a causas de género como el acoso, inseguridad, etc.

El código para la segunda pregunta es el siguiente:

prob_adulto_bajo <- cpquery(fitted_q12,
                      event = ((masDeUnCarro == "Si") | (tipoTransporte == "Privado") | (tipoTransporte == "Publico y privado")),
                      evidence = ((edad == "Adulto joven") & (estrato == "Bajo")), n = 10^6)


prob_adulto_bajo
[1] 0.8996256

Como puede observarse, la probabilidad de que un hombre entre 20 y 45 años con estrato sociodemográfico bajo tenga al menos un carro o utilice transporte privado es de aproximadamente el 0.90, lo que a primera vista podría resultar contraintuitivo debido al estrato del que se está hablando, sin embargo, también debe tomarse en cuenta que con un viaje que la persona haya realizado en transporte privado, la persona ya entra dentro de este porcentaje.

Ahora, para responder la tercera pregunta realizamos el siguiente código:

prob_viaje_habil <- cpquery(fitted_q34,
        event = (diaViaje == "Entre semana"),
        evidence = (estrato == "Bajo"), n = 10^6)

prob_viaje_no_habil <- cpquery(fitted_q34,
        event = (diaViaje == "Sabado"),
        evidence = (estrato == "Bajo"), n = 10^6)

prob_viaje_habil
[1] 0.6072389
prob_viaje_no_habil
[1] 0.3938441

Es evidente que la probabilidad de un viaje entre semana resultó ser mayor que la de un viaje en fin de semana, esto puede ser en general debido a la cantidad de días que se consideran entre semana contra solo el sábado. Aunque, sí es de resaltar que definitivamente hay una diferencia entre la cantidad de viajes que hay este día contra las que hay un solo día entre semana, lo que puede ser debido a que además de viajes realizados por trabajo, también pueden sumarse los que son debido a actividades de ocio.

Finalmente, la cuarta pregunta la podemos responder con la siguiente query:

p_pico <- cpquery(fitted_q34, 
                  event = ((tipoTransporte == "Publico") | (tipoTransporte == "Publico y privado")), 
                  evidence = (horaPico == "Si"), n = 10^6)


p_no_pico <- cpquery(fitted_q34, 
                     event = ((tipoTransporte == "Publico") | (tipoTransporte == "Publico y privado")), 
                     evidence = (horaPico == "No"), n = 10^6)

p_pico
[1] 0.3595032
p_no_pico
[1] 0.4069275

Finalmente, es de notar que la probabilidad de que un viaje en transporte público se haya realizado en hora pico es menor a si lo fue en horas de menor tráfico. Esto puede ser debido al gran margen de horas que existe fuera del horario considerado, a que en las horas pico la gente prefiera utilizar transportes privados, o a la simplificación que implica la discretización de si el viaje fue realizado en este horario. Así mismo, puede que específicamente las horas pico investigadas no apliquen a los datos de la encuesta.

Conclusiones

La movilidad en la ZMVM es un sistema muy complejo lleno de profundas desigualdades sociales y territoriales. Diariamente, millones de personas invierten una cantidad desproporcionada de su tiempo y recursos en traslados, estudiar la movilidad en la ZMVM implica adentrarse en las dinámicas de segregación espacial e inequidad social que definen la vida cotidiana de más de 20 millones de personas.

En este estudio, observamos que sí podemos encontrar desigualdades socioeconómicas y de género en el transporte urbano. Un ejemplo de ello es que se tiene una menor probabilidad de que una mujer utilice el transporte público respecto a un hombre, sugiriendo que ciertas barreras o riesgos afectan la movilidad de mujeres y hombres de manera distinta.

Para un mejor análisis consideramos la necesidad de manejar cuidadosamente la categorización y discretización de variables, como definir de manera más puntual lo que implica que un viaje se realice en hora pico o tener rangos definidos para discretizar algunas variables como `edad`, debido a que durante la discretización se puede perder información relevante o las relaciones entre algunas de las variables pueden ser modificadas.

Adicionalmente, caminar fue considerado como un transporte privado, por lo que se podrían definir diferentes tipos de categorizaciones de transportes privados y públicos para conocer mejor a qué tipo de transporte se está haciendo referencia, ya sea de tipo vehículo terrestre, subterráneo, aéreo, entre otros.

En conjunto, con estas observaciones se puede concluir que la movilidad en la ZMVM no puede entenderse de manera aislada, sino como el resultado de la interacción de múltiples factores. Los datos aquí analizados ofrecen una gran cantidad de información que puede servir para entender de mejor manera la dinámica del transporte que se tiene en esta zona, y un análisis más profundo de ellos puede llevar a observar cómo se acentúan las desigualdades en el sector transporte y a una posterior toma de acción en este rubro.

Apéndice A

El primer set de datos que se generó contiene las variables de interés relacionadas a las primeras dos preguntas, las cuales incluyen sexo, tipoTransporte, masDeUnCarro, edad y estrato. Para ello, se obtuvieron las columnas de sexo y edad desde el archivo tviaje_eod2017/conjunto_de_datos/tviaje.csv.

Variablesexo

La columna de sexo en el archivo de viajes contiene valores de 1 y 2, cuyos significados se encuentran en el catálogo vinculado a este archivo, por lo que se reemplazaron los valores de acuerdo con el catálogo en tviaje_eod2017/catalogos/sexo.csv.

Variable edad

La variable edad fue clasificada en 4 categorías:

  • Joven: Persona menor a 20 años.
  • Adulto joven: Persona entre 20 y 45 años.
  • Adulto: Persona entre 46 y 64 años.
  • Adulto mayor: Persona mayor a los 64 años.

Variable tipoTransporte

Utilizando el identificador del viaje (id\_via) dentro de este mismo conjunto de datos, se realizó una unión con los datos de transporte (archivo con la ruta ttransporte_eod2017/conjunto_de_datos/ttransporte.csv), para obtener las variables p5\_3 y p5\_14, que representan el día de viaje y el medio de transporte respectivamente. Con ello, se contó la cantidad de veces en las que se viajó en transporte público (transportes correspondientes a los números 2, 5, 6, 8, 10, 11, 12, 13, 15 en la variable p5\_14) y la cantidad de veces en las que se viajó en transporte privado (transportes correspondientes a los números 1, 3, 4, 7, 9, 14, 16, 17, 18, 19 en la variable p5\_14) por persona.

A la variable tipoTransporte se le asignó el valor “Ninguno” cuando se viajó 0 veces en transporte público y 0 veces en transporte privado, “Publico” cuando se viajó solamente en transporte público, “Privado” cuando se viajó solamente en transporte privado, y “Publico y privado” cuando se viajó por lo menos una vez en ambos tipos de transporte.

Posteriormente, se realizó una unión entre la tabla con la información de los hogares (thogar_eod2017/conjunto_de_datos/thogar.csv) y la de información sociodemográfica (tsdem_eod2017/conjunto_de_datos/tsdem.csv), para vincular a través del identificador del hogar (id\_hog) la información del identificador de la persona (id\_soc) junto con la cantidad de autos o camionetas que se tienen para transportarse diariamente (p2\_1\_1) y el estrato sociodemográfico (estrato).

Variable masDeUnCarro

Utilizando la columna de p2\_1\_1, la cantidad de autos o camionetas para transporte, se asignó el valor de “No” si se tenían 0 o 1 autos, y se asignó “Si” cuando se tenían dos o más autos.

Variable estrato

Para la variable estrato, se renombraron las categorías de acuerdo con el catálogo thogar_eod2017/catalogos/estrato.csv.

Apéndice B

El segundo set de datos se utilizará para responder las preguntas 3 y 4, las cuales tienen como variables de interés a estrato, diaViaje, tipoTransporte y horaPico. Para ello, de la información de viajes que se encuentra en tviaje_eod2017/conjunto_de_datos/tviaje.csv, se extrae el estrato sociodemográfico (estrato), la clasificación del día de viaje (p5\_3), y el horario en el que se realizó el viaje (p5\_9\_1 para la hora de inicio, p5\_9\_2 para el minuto de inicio, p5\_10\_1 para la hora de fin, p5\_10\_2 para el minuto de fin).

Variable diaViaje

La columna de la clasificación del día de viaje, p5\_3, presenta valores de 1 y 2, los cuales hacen referencia a que se viaje entre semana o a que se viaje en sábado respectivamente, de acuerdo con el catálogo que se encuentra en tviaje_eod2017/catalogos/p5_3.csv. Conociendo esto, se reemplazó el valor de 1 a “Entre semana” y el de 2 a “Sabado” para una mayor claridad en las categorías.

Varibale estrato

En la variable estrato, se renombraron las categorías de acuerdo con el catálogo thogar_eod2017/catalogos/estrato.csv.

Variable tipoTransporte

Utilizando el identificador del viaje (id\_via) en el conjunto de datos del transporte (el cual se encuentra en ttransporte_eod2017/conjunto_de_datos/ttransporte.csv), se contó en cuántas ocasiones se viajó en transporte público y en transporte privado en un solo viaje. Al igual que en el Apéndice A, se tomaron a los valores de 2, 5, 6, 8, 10, 11, 12, 13, 15 en la variable p5\_14 como transportes públicos y a los valores 1, 3, 4, 7, 9, 14, 16, 17, 18, 19 como transporte privado. A partir de este conteo, se le asignó la categoría de “Ninguno” a la variable tipoTransporte cuando no se viajó ni en transporte público ni privado, “Publico” cuando el viaje solamente se realizó en transporte público, “Privado” si el viaje solamente se realizó en transporte privado, y “Publico y privado” en caso de que el viaje se haya realizado tanto en transporte público como en transporte privado.

Variable horaPico

Para determinar si un viaje se llevó a cabo en hora pico o no, se asume que los horarios pico se encuentran entre las 7:30 y 9:30 horas, así como entre las 17:30 y 20:00 horas (MexicoCity.cdmx.gob.mx 2022). Con ello, se calculó cuántos minutos del viaje se dieron durante algún horario pico, y se dividió entre el total de minutos que duró el viaje para obtener una proporción del tiempo del viaje que se llevó a cabo en hora pico respecto a la duración total del viaje. En el caso en que el viaje se haya realizado en horario pico más de la mitad de su duración, este se considera que fue en hora pico. En caso contrario, se considera el viaje como no realizado en hora pico.

Un caso a considerar a la hora de calcular las horas picos es que existen viajes que se terminaron en una hora previa a la hora de inicio, no en una hora posterior. Esto se asume que indica que el viaje se da en dos días, por lo que a la hora de obtener cuánto tiempo del viaje se llevó a cabo en horario pico, se considera primero el tiempo desde el momento del inicio del viaje hasta el fin del día, a lo cual se le agrega el tiempo entre el inicio del día y el momento del fin del viaje.

La manera en la que se calculó la duración del viaje en horario pico es la siguiente:

  • Se tomó el valor máximo entre el inicio del viaje y el inicio del primer horario pico, al cual referiremos como a.
  • Se tomó el valor mínimo entre el fin del viaje y el fin del primer horario pico, al cual referiremos como b.
  • En caso de a<b, se considera que el tiempo b-a se realizó en horario pico. Sino, no hubo traslape con dicho horario pico.
  • Se repiten los pasos anteriores para el segundo horario pico, y se suman estos tiempos.

Para el caso particular en donde el viaje se realiza durante dos días, se secciona el horario, así que el traslape que se da en la hora de inicio hasta el final del día con los horarios pico, se le añade el traslape que se da entre el inicio del día hasta el final del viaje con los horarios pico.

Referencias

References

Alfonso, H. o. K., J. F. J. Alberto, and H. o. K. Alfonso. 2020. “Movilidad Urbana y Seguridad Vial En La Zona Metropolitana Del Valle de México. Otra Perspectiva En Torno Al Peatón y Ciclista.” Recuperado el 29 de agosto de 2025, de https://zaloamati.azc.uam.mx/items/2de88382-6bff-4afe-a550-6c484d6d2674.
Bhattarai, S. 2025. “Comprehensive Guide to Probabilistic Reasoning and Bayesian Networks.” Recuperado el 30 de agosto de 2025, de https://siddhantbhattarai.hashnode.dev/comprehensive-guide-to-probabilistic-reasoning-and-bayesian-networks.
INEGI. 2017. “Encuesta Origen Destino En Hogares de La Zona Metropolitana Del Valle de México (EOD) 2017.” https://www.inegi.org.mx/programas/eod/2017/.
Kratzer, Gilles, Fraser Lewis, Arianna Comin, Marta Pittavino, and Reinhard Furrer. 2023. “Additive Bayesian Network Modeling with the r Package Abn.” Journal of Statistical Software 105 (8): 1–41. https://doi.org/10.18637/jss.v105.i08.
MexicoCity.cdmx.gob.mx. 2022. “Conceptos Básicos Para Viajar a La Ciudad de México.” Recuperado el 31 de agosto de 2025, de https://mexicocity.cdmx.gob.mx/e/basics-for-mexico-city-travel/.
Plataforma Urbana y de Ciudades. 2023. “Movilidad Urbana Sostenible: Beneficios Sociales, Ambientales y Económicos.” Recuperado el 29 de agosto de 2025, de https://plataformaurbana.cepal.org/es/noticia/movilidad-urbana-sostenible-beneficios-sociales-ambientales-y-economicos.
Scutari, Marco, and Jean-Baptiste Denis. 2021. Bayesian Networks: With Examples in r. 2nd ed. Texts in Statistical Science. CRC Press.